#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
语音模块统一接口
Voice Module Unified Interface

提供语音模块所有功能的统一接口，包括语音唤醒、录音、播放和语音转文字
Provides unified interface for all voice module functionalities including wake detection, recording, playback and speech-to-text
"""

import os
import time
import yaml
import logging
from typing import Optional, Dict, Any, Callable, Tuple
from pathlib import Path

# 导入核心功能模块
try:
    # 尝试相对导入（作为包使用时）
    from .core.voice_wake import VoiceWakeDetector
    from .core.voice_record import VoiceRecorder
    from .core.audio_player import AudioPlayer
    from .core.speech_to_text import SpeechToTextClient
    from .core.text_to_speech import TextToSpeechClient
    from .core.audio_queue_manager import AudioQueueManager, AudioPriority
    from .utils.serial_comm import SerialCommunicator
except ImportError:
    # 回退到绝对导入（直接运行时）
    import sys
    import os
    # 添加voice_module目录到路径
    current_dir = os.path.dirname(os.path.abspath(__file__))
    sys.path.insert(0, current_dir)
    
    from core.voice_wake import VoiceWakeDetector
    from core.voice_record import VoiceRecorder
    from core.audio_player import AudioPlayer
    from core.speech_to_text import SpeechToTextClient
    from core.text_to_speech import TextToSpeechClient
    from core.audio_queue_manager import AudioQueueManager, AudioPriority
    from utils.serial_comm import SerialCommunicator


class VoiceInterface:
    """
    语音模块统一接口类
    Voice Module Unified Interface Class
    
    集成语音唤醒、录音、播放和语音转文字功能的统一接口
    Unified interface integrating wake detection, recording, playback and speech-to-text functionalities
    """
    
    def __init__(self, config_path: Optional[str] = None):
        """
        初始化语音接口
        Initialize voice interface
        
        Args:
            config_path (Optional[str]): 配置文件路径 / Configuration file path
                                       如果为None，使用默认配置 / If None, use default config
        """
        # 加载配置
        self.config = self._load_config(config_path)
        
        # 设置日志
        self._setup_logging()
        self.logger = logging.getLogger(__name__)
        
        # 初始化各个功能模块
        self.wake_detector: Optional[VoiceWakeDetector] = None
        self.recorder: Optional[VoiceRecorder] = None
        self.audio_player: Optional[AudioPlayer] = None
        self.speech_to_text: Optional[SpeechToTextClient] = None
        self.tts_client: Optional[TextToSpeechClient] = None
        self.serial_comm: Optional[SerialCommunicator] = None
        self.audio_queue_manager: Optional[AudioQueueManager] = None
        
        # 初始化状态
        self.is_initialized = False
        
        self.logger.info("VoiceInterface initialized")
    
    def _load_config(self, config_path: Optional[str] = None) -> Dict[str, Any]:
        """
        加载配置文件
        Load configuration file
        
        Args:
            config_path (Optional[str]): 配置文件路径 / Configuration file path
            
        Returns:
            Dict[str, Any]: 配置字典 / Configuration dictionary
        """
        if config_path is None:
            # 使用默认配置文件路径
            current_dir = Path(__file__).parent
            config_path = current_dir / "config" / "voice_config.yaml"
        
        try:
            with open(config_path, 'r', encoding='utf-8') as f:
                config = yaml.safe_load(f)
            return config
        except Exception as e:
            print(f"Warning: Failed to load config file {config_path}: {e}")
            return self._get_default_config()
    
    def _get_default_config(self) -> Dict[str, Any]:
        """
        获取默认配置
        Get default configuration
        
        Returns:
            Dict[str, Any]: 默认配置字典 / Default configuration dictionary
        """
        return {
            'voice_wake': {
                'serial_port': '/dev/myspeech',
                'baudrate': 115200,
                'timeout': 1.0,
                'auto_start': True
            },
            'voice_record': {
                'sample_rate': 16000,
                'frame_duration_ms': 30,
                'vad_mode': 2,
                'max_silence_frames': 60,
                'min_speech_frames': 10,
                'mic_index': None,
                'output_dir': './audio/recorded'
            },
            'audio_player': {
                'system_sounds_dir': './audio/system_sounds',
                'default_volume': 0.8,
                'output_device_index': None,
                'auto_heal_system_sounds': True
            },
            'speech_to_text': {
                'app_id': '',
                'api_key': '',
                'api_secret': '',
                'domain': 'iat',
                'language': 'zh_cn',
                'accent': 'mandarin',
                'vad_eos': 10000,
                'frame_size': 8000,
                'send_interval': 0.04
            },
            'text_to_speech': {
                'app_id': '',
                'api_key': '',
                'api_secret': '',
                'voice_name': 'x4_yezi',
                'audio_format': 'raw',
                'sample_rate': 16000,
                'output_dir': './audio/tts_output'
            },
            'logging': {
                'level': 'INFO',
                'format': '%(asctime)s - %(name)s - %(levelname)s - %(message)s',
                'file': None
            }
        }
    
    def _setup_logging(self):
        """
        设置日志配置
        Setup logging configuration
        """
        log_config = self.config.get('logging', {})
        log_level = getattr(logging, log_config.get('level', 'INFO').upper())
        log_format = log_config.get('format', '%(asctime)s - %(name)s - %(levelname)s - %(message)s')
        log_file = log_config.get('file')
        
        logging.basicConfig(
            level=log_level,
            format=log_format,
            filename=log_file
        )
    
    def _get_stt_credentials(self) -> Optional[Dict[str, Any]]:
        """
        解析并返回可用于初始化的STT凭据（向后兼容不同配置结构）
        Resolve and return STT credentials compatible with both flat and provider-nested schemas.
        
        支持两种结构：
        1) 扁平结构（voice_config.yaml）：
           speech_to_text: { app_id, api_key, api_secret, ... }
        2) provider嵌套结构（test_config.yaml）：
           speech_to_text: { enabled, provider: "xunfei", xunfei: { app_id, api_key, api_secret, ... }, ... }
        
        Returns:
            Optional[Dict[str, Any]]: 若配置完备返回凭据字典，否则返回None
        """
        stt_section = self.config.get('speech_to_text', {}) or {}
        
        # Respect explicit enabled flag if present
        enabled = stt_section.get('enabled', None)
        if enabled is not None and not enabled:
            return None
        
        # Case 1: flat schema
        flat_app = stt_section.get('app_id')
        flat_key = stt_section.get('api_key')
        flat_secret = stt_section.get('api_secret')
        if flat_app and flat_key and flat_secret:
            # Keep other optional parameters
            creds = {
                'app_id': flat_app,
                'api_key': flat_key,
                'api_secret': flat_secret,
            }
            for k in ('domain', 'language', 'accent', 'vad_eos', 'frame_size', 'send_interval'):
                if k in stt_section:
                    creds[k] = stt_section[k]
            return creds
        
        # Case 2: provider-nested schema
        provider = stt_section.get('provider')
        if provider:
            provider_key = str(provider).lower()
            provider_cfg = stt_section.get(provider_key, {}) or stt_section.get(provider, {}) or {}
            app = provider_cfg.get('app_id')
            key = provider_cfg.get('api_key')
            secret = provider_cfg.get('api_secret')
            if app and key and secret:
                creds = {
                    'app_id': app,
                    'api_key': key,
                    'api_secret': secret,
                }
                # Provider-specific optional params have higher priority
                for k in ('domain', 'language', 'accent', 'vad_eos', 'frame_size', 'send_interval'):
                    if k in provider_cfg:
                        creds[k] = provider_cfg[k]
                    elif k in stt_section:
                        creds[k] = stt_section[k]
                # Pass through optional URL if present (client may ignore if not used)
                if 'url' in provider_cfg:
                    creds['url'] = provider_cfg['url']
                return creds
        
        return None
    
    def _get_tts_credentials(self) -> Optional[Dict[str, Any]]:
        """
        解析并返回可用于初始化的TTS凭据（向后兼容不同配置结构）
        Resolve and return TTS credentials compatible with both flat and provider-nested schemas.
        
        支持两种结构：
        1) 扁平结构（voice_config.yaml）：
           text_to_speech: { app_id, api_key, api_secret, ... }
        2) provider嵌套结构（test_config.yaml）：
           text_to_speech: { enabled, provider: "xunfei", xunfei: { app_id, api_key, api_secret, ... }, ... }
        
        Returns:
            Optional[Dict[str, Any]]: 若配置完备返回凭据字典，否则返回None
        """
        tts_section = self.config.get('text_to_speech', {}) or {}
        
        # Respect explicit enabled flag if present
        enabled = tts_section.get('enabled', None)
        if enabled is not None and not enabled:
            return None
        
        # Case 1: flat schema
        flat_app = tts_section.get('app_id')
        flat_key = tts_section.get('api_key')
        flat_secret = tts_section.get('api_secret')
        if flat_app and flat_key and flat_secret:
            # Keep other optional parameters
            creds = {
                'app_id': flat_app,
                'api_key': flat_key,
                'api_secret': flat_secret,
            }
            for k in ('voice_name', 'audio_format', 'sample_rate', 'output_dir'):
                if k in tts_section:
                    creds[k] = tts_section[k]
            return creds
        
        # Case 2: provider-nested schema
        provider = tts_section.get('provider')
        if provider:
            provider_key = str(provider).lower()
            provider_cfg = tts_section.get(provider_key, {}) or tts_section.get(provider, {}) or {}
            app = provider_cfg.get('app_id')
            key = provider_cfg.get('api_key')
            secret = provider_cfg.get('api_secret')
            if app and key and secret:
                creds = {
                    'app_id': app,
                    'api_key': key,
                    'api_secret': secret,
                }
                # Provider-specific optional params have higher priority
                for k in ('voice_name', 'audio_format', 'sample_rate', 'output_dir'):
                    if k in provider_cfg:
                        creds[k] = provider_cfg[k]
                    elif k in tts_section:
                        creds[k] = tts_section[k]
                return creds
        
        return None
    
    def initialize_all(self) -> Tuple[bool, str, None]:
        """
        初始化所有功能模块
        Initialize all functional modules
        
        Returns:
            Tuple[bool, str, None]: (success, message, data)
        """
        try:
            # 初始化语音唤醒检测器
            if self.config.get('voice_wake', {}).get('auto_start', True):
                success, msg, _ = self.initialize_wake_detector()
                if not success:
                    return False, f"Wake detector initialization failed: {msg}", None
            
            # 初始化录音器
            success, msg, _ = self.initialize_recorder()
            if not success:
                return False, f"Recorder initialization failed: {msg}", None
            
            # 初始化音频播放器
            success, msg, _ = self.initialize_audio_player()
            if not success:
                return False, f"Audio player initialization failed: {msg}", None
            
            # 初始化语音转文字（兼容两种配置结构并尊重enabled标志）
            if self._get_stt_credentials() is not None:
                success, msg, _ = self.initialize_speech_to_text()
                if not success:
                    return False, f"Speech to text initialization failed: {msg}", None
            
            # 初始化文字转语音（兼容两种配置结构并尊重enabled标志）
            if self._get_tts_credentials() is not None:
                success, msg, _ = self.initialize_text_to_speech()
                if not success:
                    return False, f"Text to speech initialization failed: {msg}", None
            
            # 初始化音频队列管理器
            success, msg, _ = self.initialize_audio_queue_manager()
            if not success:
                return False, f"Audio queue manager initialization failed: {msg}", None
            
            self.is_initialized = True
            self.logger.info("All voice modules initialized successfully")
            return True, "All voice modules initialized successfully", None
            
        except Exception as e:
            self.logger.error(f"Failed to initialize voice modules: {e}")
            return False, f"Failed to initialize voice modules: {str(e)}", None
    
    def initialize_wake_detector(self) -> Tuple[bool, str, None]:
        """
        初始化语音唤醒检测器
        Initialize voice wake detector
        
        Returns:
            Tuple[bool, str, None]: (success, message, data)
        """
        try:
            wake_config = self.config.get('voice_wake', {})
            self.wake_detector = VoiceWakeDetector(wake_config)
            
            # 初始化串口通信
            self.serial_comm = SerialCommunicator(
                port=wake_config.get('serial_port', '/dev/myspeech'),
                baudrate=wake_config.get('baudrate', 115200)
            )
            
            self.logger.info("Voice wake detector initialized")
            return True, "Voice wake detector initialized successfully", None
        except Exception as e:
            self.logger.error(f"Failed to initialize wake detector: {e}")
            return False, f"Failed to initialize wake detector: {str(e)}", None
    
    def initialize_recorder(self) -> Tuple[bool, str, None]:
        """
        初始化录音器
        Initialize voice recorder
        
        Returns:
            Tuple[bool, str, None]: (success, message, data)
        """
        try:
            record_config = self.config.get('voice_record', {})
            self.recorder = VoiceRecorder(record_config)
            self.logger.info("Voice recorder initialized")
            return True, "Voice recorder initialized successfully", None
        except Exception as e:
            self.logger.error(f"Failed to initialize recorder: {e}")
            return False, f"Failed to initialize recorder: {str(e)}", None
    
    def initialize_audio_player(self) -> Tuple[bool, str, None]:
        """
        初始化音频播放器
        Initialize audio player
        
        Returns:
            Tuple[bool, str, None]: (success, message, data)
        """
        try:
            player_config = self.config.get('audio_player', {})
            self.audio_player = AudioPlayer(player_config)
            self.logger.info("Audio player initialized")
            return True, "Audio player initialized successfully", None
        except Exception as e:
            self.logger.error(f"Failed to initialize audio player: {e}")
            return False, f"Failed to initialize audio player: {str(e)}", None
    
    def initialize_speech_to_text(self) -> Tuple[bool, str, None]:
        """
        初始化语音转文字
        Initialize speech to text
        
        Returns:
            Tuple[bool, str, None]: (success, message, data)
        """
        try:
            stt_creds = self._get_stt_credentials()
            if not stt_creds:
                return False, "Speech to text is disabled or not configured", None
            self.stt_client = SpeechToTextClient(stt_creds)
            
            self.logger.info("Speech to text initialized successfully")
            return True, "Speech to text initialized successfully", None
        except Exception as e:
            self.logger.error(f"Failed to initialize speech to text: {e}")
            return False, f"Failed to initialize speech to text: {str(e)}", None
    
    def initialize_text_to_speech(self) -> Tuple[bool, str, None]:
        """
        初始化文字转语音客户端
        Initialize text to speech client
        
        Returns:
            Tuple[bool, str, None]: (success, message, data)
        """
        try:
            credentials = self._get_tts_credentials()
            if credentials is None:
                return False, "TTS credentials not found or incomplete", None
            
            # 提取基本认证参数
            auth_params = {
                'app_id': credentials['app_id'],
                'api_key': credentials['api_key'],
                'api_secret': credentials['api_secret']
            }
            
            # 创建TTS客户端
            self.tts_client = TextToSpeechClient(**auth_params)
            
            # 设置语音参数
            voice_name = credentials.get('voice_name', 'x4_yezi')
            audio_format = credentials.get('audio_format', 'raw')
            sample_rate = credentials.get('sample_rate', 16000)
            self.tts_client.set_voice_parameters(voice_name, audio_format, sample_rate)
            
            # 设置输出目录
            output_dir = credentials.get('output_dir', './audio/tts_output')
            if hasattr(self.tts_client, 'output_dir'):
                self.tts_client.output_dir = output_dir
            
            self.logger.info("Text to speech client initialized successfully")
            return True, "Text to speech client initialized successfully", None
            
        except Exception as e:
            self.logger.error(f"Failed to initialize text to speech: {e}")
            return False, f"Failed to initialize text to speech: {str(e)}", None
    
    def initialize_audio_queue_manager(self) -> Tuple[bool, str, None]:
        """
        初始化音频队列管理器
        Initialize audio queue manager
        
        Returns:
            Tuple[bool, str, None]: (success, message, data)
        """
        try:
            if self.audio_player is None:
                return False, "Audio player must be initialized before queue manager", None
            
            # 获取队列配置
            queue_config = self.config.get('audio_queue', {})
            
            self.audio_queue_manager = AudioQueueManager(
                audio_player=self.audio_player,
                config=queue_config
            )
            
            self.logger.info("Audio queue manager initialized successfully")
            return True, "Audio queue manager initialized successfully", None
            
        except Exception as e:
            self.logger.error(f"Failed to initialize audio queue manager: {e}")
            return False, f"Failed to initialize audio queue manager: {str(e)}", None
    
    # 语音唤醒相关方法 / Wake detection related methods
    def start_wake_detection(self) -> Tuple[bool, str, None]:
        """
        开始语音唤醒检测
        Start voice wake detection
        
        Returns:
            Tuple[bool, str, None]: (success, message, data)
        """
        self.logger.info("[DEBUG] start_wake_detection called")
        if not self.wake_detector:
            self.logger.warning("Wake detector not initialized")
            return False, "Wake detector not initialized", None
        
        self.logger.info(f"[DEBUG] Wake detector exists: {type(self.wake_detector)}")
        try:
            self.logger.info("[DEBUG] Calling wake_detector.start()")
            success = self.wake_detector.start()
            self.logger.info(f"[DEBUG] wake_detector.start() returned: {success}")
            if success:
                self.logger.info("[DEBUG] Wake detection started successfully")
                return True, "Wake detection started successfully", None
            else:
                self.logger.warning("[DEBUG] Failed to start wake detection - start() returned False")
                return False, "Failed to start wake detection", None
        except Exception as e:
            self.logger.error(f"[DEBUG] Exception in start_wake_detection: {e}")
            return False, f"Failed to start wake detection: {str(e)}", None
    
    def stop_wake_detection(self) -> Tuple[bool, str, None]:
        """
        停止语音唤醒检测
        Stop voice wake detection
        
        Returns:
            Tuple[bool, str, None]: (success, message, data)
        """
        if not self.wake_detector:
            return True, "Wake detector not initialized, nothing to stop", None
        
        try:
            self.wake_detector.stop()
            return True, "Wake detection stopped successfully", None
        except Exception as e:
            self.logger.error(f"Failed to stop wake detection: {e}")
            return False, f"Failed to stop wake detection: {str(e)}", None
    
    def is_wake_detected(self) -> Tuple[bool, str, bool]:
        """
        检查是否检测到唤醒
        Check if wake is detected
        
        Returns:
            Tuple[bool, str, bool]: (success, message, wake_detected)
        """
        if not self.wake_detector:
            self.logger.warning("[DEBUG] Wake detector not initialized in is_wake_detected")
            return False, "Wake detector not initialized", False
        try:
            # VoiceWakeDetector没有is_wake_detected方法，使用wait_for_wake(0)进行非阻塞检查
            self.logger.debug("[DEBUG] Calling wake_detector.wait_for_wake(timeout=0)")
            wake_detected = self.wake_detector.wait_for_wake(timeout=0)
            self.logger.debug(f"[DEBUG] wait_for_wake returned: {wake_detected}")
            return True, "Wake detection check completed", wake_detected
        except Exception as e:
            self.logger.error(f"[DEBUG] Exception in is_wake_detected: {e}")
            return False, f"Failed to check wake detection: {str(e)}", False
    
    # 录音相关方法 / Recording related methods
    def start_recording(self, filename: Optional[str] = None, 
                       duration: Optional[float] = None,
                       use_vad: Optional[bool] = None) -> Tuple[bool, str, None]:
        """
        开始录音（兼容模式，默认使用固定时长录制）
        Start recording (compatibility mode, defaults to fixed duration recording)
        
        Args:
            filename (Optional[str]): 录音文件名 / Recording filename
            duration (Optional[float]): 录音时长(秒) / Recording duration in seconds
            use_vad (Optional[bool]): 是否使用VAD检测，None表示自动判断 / Whether to use VAD detection, None for auto decision
            
        Returns:
            Tuple[bool, str, None]: (success, message, data)
        """
        if not self.recorder:
            self.logger.warning("Recorder not initialized")
            return False, "Recorder not initialized", None
        
        try:
            self.recorder.start_continuous_recording(filename, duration, use_vad)
            return True, "Recording started successfully", None
        except Exception as e:
            self.logger.error(f"Failed to start recording: {e}")
            return False, f"Failed to start recording: {str(e)}", None
    
    def start_segment_recording(self, base_filename: Optional[str] = None,
                               min_segment_frames: Optional[int] = None) -> Tuple[bool, str, None]:
        """
        开始连续分段录音（VAD模式）
        Start continuous segment recording (VAD mode)
        
        Args:
            base_filename (Optional[str]): 基础文件名，会自动添加序号 / Base filename, sequence number will be added
            min_segment_frames (Optional[int]): 最小分段帧数 / Minimum segment frames
            
        Returns:
            Tuple[bool, str, None]: (success, message, data)
        """
        if not self.recorder:
            self.logger.warning("Recorder not initialized")
            return False, "Recorder not initialized", None
        
        try:
            self.recorder.start_continuous_segment_recording(base_filename, min_segment_frames)
            return True, "Segment recording started successfully", None
        except Exception as e:
            self.logger.error(f"Failed to start segment recording: {e}")
            return False, f"Failed to start segment recording: {str(e)}", None
    
    def start_single_segment_recording(self, base_filename: Optional[str] = None,
                                      min_segment_frames: Optional[int] = None) -> Tuple[bool, str, None]:
        """
        开始单段录音（录制完第一段后立即停止）
        Start single segment recording (stops after first segment)
        
        Args:
            base_filename (Optional[str]): 基础文件名，会自动添加序号 / Base filename, sequence number will be added
            min_segment_frames (Optional[int]): 最小分段帧数 / Minimum segment frames
            
        Returns:
            Tuple[bool, str, None]: (success, message, data)
        """
        if not self.recorder:
            self.logger.warning("Recorder not initialized")
            return False, "Recorder not initialized", None
        
        try:
            self.recorder.start_single_segment_recording(base_filename, min_segment_frames)
            return True, "Single segment recording started successfully", None
        except Exception as e:
            self.logger.error(f"Failed to start single segment recording: {e}")
            return False, f"Failed to start single segment recording: {str(e)}", None
    

    def start_fixed_recording(self, filename: Optional[str] = None,
                             duration: Optional[float] = None) -> Tuple[bool, str, None]:
        """
        开始固定时长录音
        Start fixed duration recording
        
        Args:
            filename (Optional[str]): 录音文件名 / Recording filename
            duration (Optional[float]): 录音时长(秒) / Recording duration in seconds
            
        Returns:
            Tuple[bool, str, None]: (success, message, data)
        """
        if not self.recorder:
            self.logger.warning("Recorder not initialized")
            return False, "Recorder not initialized", None
        
        try:
            self.recorder.start_continuous_recording(filename, duration)
            return True, "Fixed duration recording started successfully", None
        except Exception as e:
            self.logger.error(f"Failed to start fixed duration recording: {e}")
            return False, f"Failed to start fixed duration recording: {str(e)}", None
    
    def stop_recording(self) -> Tuple[bool, str, Optional[str]]:
        """
        停止录音
        Stop recording
        
        Returns:
            Tuple[bool, str, Optional[str]]: (success, message, recording_file_path)
        """
        if not self.recorder:
            return False, "Recorder not initialized", None
        
        try:
            file_path = self.recorder.stop_recording()
            if file_path:
                return True, "Recording stopped successfully", file_path
            else:
                # 检查是否是因为没有检测到语音而结束的录音
                if hasattr(self.recorder, 'is_recording') and not self.recorder.is_recording:
                    return True, "Recording completed but no speech detected", None
                else:
                    return False, "No recording to stop", None
        except Exception as e:
            self.logger.error(f"Failed to stop recording: {e}")
            return False, f"Failed to stop recording: {str(e)}", None
    
    def is_recording(self) -> Tuple[bool, str, bool]:
        """
        检查是否正在录音
        Check if recording
        
        Returns:
            Tuple[bool, str, bool]: (success, message, is_recording)
        """
        if not self.recorder:
            return True, "Recorder not initialized", False
        try:
            recording_status = self.recorder.is_recording
            return True, "Recording status checked successfully", recording_status
        except Exception as e:
            self.logger.error(f"Failed to check recording status: {e}")
            return False, f"Failed to check recording status: {str(e)}", False
    
    # 音频播放相关方法 / Audio playback related methods
    def play_audio(self, file_path: str, volume: Optional[float] = None) -> Tuple[bool, str, None]:
        """
        播放音频文件
        Play audio file
        
        Args:
            file_path (str): 音频文件路径 / Audio file path
            volume (Optional[float]): 播放音量 / Playback volume
            
        Returns:
            Tuple[bool, str, None]: (success, message, data)
        """
        if not self.audio_player:
            self.logger.warning("Audio player not initialized")
            return False, "Audio player not initialized", None
        
        try:
            success = self.audio_player.play_file(file_path, volume)
            if success:
                return True, "Audio playback started successfully", None
            else:
                return False, "Failed to start audio playback", None
        except Exception as e:
            self.logger.error(f"Failed to play audio: {e}")
            return False, f"Failed to play audio: {str(e)}", None
    
    def stop_audio(self) -> Tuple[bool, str, None]:
        """
        停止音频播放
        Stop audio playback
        
        Returns:
            Tuple[bool, str, None]: (success, message, data)
        """
        if not self.audio_player:
            return True, "Audio player not initialized, nothing to stop", None
        
        try:
            self.audio_player.stop_playback()
            return True, "Audio playback stopped successfully", None
        except Exception as e:
            self.logger.error(f"Failed to stop audio: {e}")
            return False, f"Failed to stop audio: {str(e)}", None
    
    def play_system_sound(self, sound_name: str) -> Tuple[bool, str, None]:
        """
        播放系统提示音
        Play system sound
        
        Args:
            sound_name (str): 提示音名称 / Sound name
            
        Returns:
            Tuple[bool, str, None]: (success, message, data)
        """
        if not self.audio_player:
            self.logger.warning("Audio player not initialized")
            return False, "Audio player not initialized", None
        
        try:
            success = self.audio_player.play_system_sound(sound_name)
            if success:
                return True, "System sound played successfully", None
            else:
                return False, "Failed to play system sound", None
        except Exception as e:
            self.logger.error(f"Failed to play system sound: {e}")
            return False, f"Failed to play system sound: {str(e)}", None
    
    # 语音转文字相关方法 / Speech to text related methods
    def recognize_audio_file(self, audio_file_path: str) -> Tuple[bool, str, Optional[str]]:
        """
        识别音频文件中的语音
        Recognize speech in audio file
        
        Args:
            audio_file_path (str): 音频文件路径 / Audio file path
            
        Returns:
            Tuple[bool, str, Optional[str]]: (success, message, recognition_result)
        """
        if not self.stt_client:
            self.logger.warning("Speech to text not initialized")
            return False, "Speech to text not initialized", None
        
        try:
            result = self.stt_client.recognize_audio_file(audio_file_path)
            if result:
                return True, "Audio recognition completed successfully", result
            else:
                return False, "No speech recognized in audio file", None
        except Exception as e:
            self.logger.error(f"Failed to recognize audio: {e}")
            return False, f"Failed to recognize audio: {str(e)}", None
    
    def set_stt_callbacks(self, 
                         on_result: Optional[Callable[[str], None]] = None,
                         on_error: Optional[Callable[[str, int], None]] = None) -> Tuple[bool, str, None]:
        """
        设置语音转文字回调函数
        Set speech to text callback functions
        
        Args:
            on_result: 识别结果回调 / Recognition result callback
            on_error: 错误回调 / Error callback
            
        Returns:
            Tuple[bool, str, None]: (success, message, data)
        """
        if not self.stt_client:
            self.logger.warning("Speech to text not initialized")
            return False, "Speech to text not initialized", None
        
        try:
            self.stt_client.set_callbacks(on_result, on_error)
            return True, "STT callbacks set successfully", None
        except Exception as e:
            self.logger.error(f"Failed to set STT callbacks: {e}")
            return False, f"Failed to set STT callbacks: {str(e)}", None
    
    # 文字转语音相关方法 / Text to speech related methods
    def synthesize_speech(self, text: str, output_file: Optional[str] = None, max_retries: int = 3) -> Tuple[bool, str, Optional[str]]:
        """
        将文字转换为语音文件
        Convert text to speech file
        
        Args:
            text (str): 要转换的文字 / Text to convert
            output_file (Optional[str]): 输出文件路径，如果不指定则自动生成 / Output file path, auto-generated if not specified
            max_retries (int): 最大重试次数 / Maximum retry attempts
            
        Returns:
            Tuple[bool, str, Optional[str]]: (success, message, output_file_path)
        """
        if not hasattr(self, 'tts_client') or not self.tts_client:
            self.logger.warning("Text to speech not initialized")
            return False, "Text to speech not initialized", None
        
        # 输入验证
        if not text or not text.strip():
            return False, "Text cannot be empty", None
        
        try:
            # 使用TTS客户端的重试机制
            success, msg, audio_data = self.tts_client.synthesize_text(text, output_file, max_retries)
            if success and audio_data:
                # 如果指定了输出文件，返回文件路径
                if output_file:
                    self.logger.info(f"Speech synthesized successfully: {output_file}")
                    return True, "Speech synthesized successfully", output_file
                else:
                    # 如果没有指定输出文件，生成临时文件
                    import tempfile
                    import os
                    temp_dir = os.path.join(os.getcwd(), 'audio', 'tts_output')
                    os.makedirs(temp_dir, exist_ok=True)
                    temp_file = os.path.join(temp_dir, f"tts_{int(time.time())}.wav")
                    
                    # 保存音频数据到文件
                    save_success, save_msg = self.tts_client._save_audio_to_file(audio_data, temp_file)
                    if save_success:
                        self.logger.info(f"Speech synthesized successfully: {temp_file}")
                        return True, "Speech synthesized successfully", temp_file
                    else:
                        self.logger.error(f"Failed to save audio file: {save_msg}")
                        return False, f"Failed to save audio file: {save_msg}", None
            else:
                self.logger.error(f"TTS synthesis failed: {msg}")
                return False, f"Failed to synthesize speech: {msg}", None
        except Exception as e:
            self.logger.error(f"Failed to synthesize speech: {e}")
            return False, f"Failed to synthesize speech: {str(e)}", None
    
    def text_to_speech(self, text: str, output_file: Optional[str] = None) -> Tuple[bool, str, Optional[str]]:
        """文字转语音的别名方法，兼容旧版本调用"""
        return self.synthesize_speech(text, output_file)
    
    def play_audio_file(self, file_path: str, volume: Optional[float] = None) -> Tuple[bool, str]:
        """播放音频文件的简化方法"""
        success, message, _ = self.play_audio(file_path, volume)
        return success, message
    
    def play_synthesized_speech(self, text: str, volume: Optional[float] = None, 
                               priority: AudioPriority = AudioPriority.NORMAL, 
                               use_queue: bool = True) -> Tuple[bool, str, None]:
        """
        将文字转换为语音并播放
        Convert text to speech and play it
        
        Args:
            text (str): 要转换并播放的文字 / Text to convert and play
            volume (Optional[float]): 播放音量 / Playback volume
            priority (AudioPriority): 播放优先级 / Playback priority
            use_queue (bool): 是否使用队列播放 / Whether to use queue playback
            
        Returns:
            Tuple[bool, str, None]: (success, message, data)
        """
        try:
            # 合成语音
            success, msg, audio_file = self.synthesize_speech(text)
            if not success or not audio_file:
                return False, f"Failed to synthesize speech: {msg}", None
            
            # 根据配置选择播放方式
            if use_queue and self.audio_queue_manager:
                # 使用队列播放
                success, msg, _ = self.add_audio_to_queue(audio_file, priority, volume)
                if not success:
                    return False, f"Failed to add synthesized speech to queue: {msg}", None
                return True, "Synthesized speech added to queue successfully", None
            else:
                # 直接播放（兼容旧版本）
                success, msg, _ = self.play_audio(audio_file, volume)
                if not success:
                    return False, f"Failed to play synthesized speech: {msg}", None
                
                # 等待音频播放完成
                if self.audio_player and hasattr(self.audio_player, 'is_playing'):
                    while self.audio_player.is_playing:
                        time.sleep(0.1)  # 短暂休眠，避免CPU占用过高
                
                return True, "Synthesized speech played successfully", None
            
        except Exception as e:
            self.logger.error(f"Failed to play synthesized speech: {e}")
            return False, f"Failed to play synthesized speech: {str(e)}", None
    
    # 组合功能方法 / Combined functionality methods
    def record_and_recognize(self, duration: Optional[float] = None) -> Tuple[bool, str, Optional[str]]:
        """
        录音并识别语音
        Record and recognize speech
        
        Args:
            duration (Optional[float]): 录音时长(秒) / Recording duration in seconds
            
        Returns:
            Tuple[bool, str, Optional[str]]: (success, message, recognition_result)
        """
        try:
            # 开始录音
            success, msg, _ = self.start_recording(duration=duration)
            if not success:
                return False, f"Failed to start recording: {msg}", None
            
            # 等待录音完成或手动停止
            if duration:
                import time
                time.sleep(duration)
            
            # 停止录音并获取文件路径
            success, msg, audio_file = self.stop_recording()
            if not success or not audio_file:
                return False, f"Failed to stop recording: {msg}", None
            
            # 识别语音
            success, msg, result = self.recognize_audio_file(audio_file)
            if success:
                return True, "Recording and recognition completed successfully", result
            else:
                return False, f"Recognition failed: {msg}", None
                
        except Exception as e:
            self.logger.error(f"Failed to record and recognize: {e}")
            return False, f"Failed to record and recognize: {str(e)}", None
    
    def wait_for_wake_and_record(self, record_duration: float = 5.0) -> Tuple[bool, str, Optional[str]]:
        """
        等待语音唤醒并录音识别
        Wait for voice wake and record with recognition
        
        Args:
            record_duration (float): 录音时长(秒) / Recording duration in seconds
            
        Returns:
            Tuple[bool, str, Optional[str]]: (success, message, recognition_result)
        """
        if not self.wake_detector:
            self.logger.warning("Wake detector not initialized")
            return False, "Wake detector not initialized", None
        
        try:
            # 开始唤醒检测
            success, msg, _ = self.start_wake_detection()
            if not success:
                return False, f"Failed to start wake detection: {msg}", None
            
            # 等待唤醒
            self.logger.info("Waiting for voice wake...")
            success, msg, wake_detected = self.is_wake_detected()
            while success and not wake_detected:
                import time
                time.sleep(0.1)
                success, msg, wake_detected = self.is_wake_detected()
            
            if not success:
                return False, f"Wake detection failed: {msg}", None
            
            self.logger.info("Wake detected! Starting recording...")
            
            # 播放提示音（如果有）
            self.play_system_sound("recording_start")
            
            # 录音并识别
            success, msg, result = self.record_and_recognize(record_duration)
            
            # 播放结束提示音
            self.play_system_sound("recording_end")
            
            if success:
                return True, "Wake detection and recording completed successfully", result
            else:
                return False, f"Recording failed: {msg}", None
            
        except Exception as e:
            self.logger.error(f"Failed in wake and record process: {e}")
            return False, f"Failed in wake and record process: {str(e)}", None
        finally:
            # 停止唤醒检测
            self.stop_wake_detection()
    
    def get_module_status(self) -> Tuple[bool, str, Dict[str, bool]]:
        """
        获取各模块状态
        Get module status
        
        Returns:
            Tuple[bool, str, Dict[str, bool]]: (success, message, module_status)
        """
        try:
            status = {
                'wake_detector': self.wake_detector is not None,
                'recorder': self.recorder is not None,
                'audio_player': self.audio_player is not None,
                'speech_to_text': self.stt_client is not None,
                'text_to_speech': self.tts_client is not None,
                'serial_comm': self.serial_comm is not None,
                'is_initialized': self.is_initialized
            }
            return True, "Module status retrieved successfully", status
        except Exception as e:
            self.logger.error(f"Failed to get module status: {e}")
            return False, f"Failed to get module status: {str(e)}", {}
    
    # 音频队列管理方法 / Audio queue management methods
    def add_audio_to_queue(self, file_path: str, priority: AudioPriority = AudioPriority.NORMAL, 
                          volume: Optional[float] = None, callback: Optional[Callable] = None) -> Tuple[bool, str, None]:
        """
        添加音频到播放队列
        Add audio to playback queue
        
        Args:
            file_path (str): 音频文件路径 / Audio file path
            priority (AudioPriority): 播放优先级 / Playback priority
            volume (Optional[float]): 音量 / Volume
            callback (Optional[Callable]): 播放完成回调 / Completion callback
            
        Returns:
            Tuple[bool, str, None]: (success, message, data)
        """
        try:
            if self.audio_queue_manager is None:
                return False, "Audio queue manager not initialized", None
            
            task_id = self.audio_queue_manager.add_audio(file_path, priority, volume, callback)
            return True, f"Audio added to queue with ID: {task_id}", None
            
        except Exception as e:
            self.logger.error(f"Failed to add audio to queue: {e}")
            return False, f"Failed to add audio to queue: {str(e)}", None
    
    def clear_audio_queue(self) -> Tuple[bool, str, None]:
        """
        清空音频播放队列
        Clear audio playback queue
        
        Returns:
            Tuple[bool, str, None]: (success, message, data)
        """
        try:
            if self.audio_queue_manager is None:
                return False, "Audio queue manager not initialized", None
            
            self.audio_queue_manager.clear_queue()
            return True, "Audio queue cleared successfully", None
            
        except Exception as e:
            self.logger.error(f"Failed to clear audio queue: {e}")
            return False, f"Failed to clear audio queue: {str(e)}", None
    
    def interrupt_audio_playback(self) -> Tuple[bool, str, None]:
        """
        立即打断当前音频播放并清空队列
        Immediately interrupt current audio playback and clear queue
        
        Returns:
            Tuple[bool, str, None]: (success, message, data)
        """
        try:
            if self.audio_queue_manager is None:
                return False, "Audio queue manager not initialized", None
            
            self.audio_queue_manager.interrupt_playback()
            return True, "Audio playback interrupted successfully", None
            
        except Exception as e:
            self.logger.error(f"Failed to interrupt audio playback: {e}")
            return False, f"Failed to interrupt audio playback: {str(e)}", None
    
    def get_queue_status(self) -> Tuple[bool, str, Optional[Dict[str, Any]]]:
        """
        获取音频队列状态
        Get audio queue status
        
        Returns:
            Tuple[bool, str, Optional[Dict[str, Any]]]: (success, message, status_data)
        """
        try:
            if self.audio_queue_manager is None:
                return False, "Audio queue manager not initialized", None
            
            status = {
                'queue_size': self.audio_queue_manager.get_queue_size(),
                'is_playing': self.audio_queue_manager.is_playing(),
                'current_task': self.audio_queue_manager.get_current_task_id()
            }
            
            return True, "Queue status retrieved successfully", status
            
        except Exception as e:
            self.logger.error(f"Failed to get queue status: {e}")
            return False, f"Failed to get queue status: {str(e)}", None
    
    def cleanup(self) -> Tuple[bool, str, None]:
        """
        清理资源
        Cleanup resources
        
        Returns:
            Tuple[bool, str, None]: (success, message, data)
        """
        try:
            if self.audio_queue_manager:
                self.audio_queue_manager.cleanup()
            
            if self.wake_detector:
                self.stop_wake_detection()
            
            if self.recorder and self.recorder.is_recording:
                self.stop_recording()
            
            if self.audio_player:
                self.stop_audio()
            
            if self.stt_client and hasattr(self.stt_client, 'destroy'):
                try:
                    self.stt_client.destroy()
                except Exception as stt_error:
                    self.logger.error(f"Error destroying STT client: {stt_error}")
            
            if self.tts_client:
                # TTS客户端通常不需要特殊清理，但可以在这里添加必要的清理逻辑
                pass
            
            if self.serial_comm and hasattr(self.serial_comm, 'close'):
                self.serial_comm.close()
            
            self.logger.info("Voice interface cleanup completed")
            return True, "Voice interface cleanup completed successfully", None
            
        except Exception as e:
            self.logger.error(f"Error during cleanup: {e}")
            return False, f"Error during cleanup: {str(e)}", None
    
    def __enter__(self):
        """上下文管理器入口 / Context manager entry"""
        return self
    
    def __exit__(self, exc_type, exc_val, exc_tb):
        """上下文管理器退出 / Context manager exit"""
        self.cleanup()


# 便捷函数 / Convenience functions
def create_voice_interface(config_path: Optional[str] = None, 
                          initialize_all: bool = True) -> Tuple[bool, str, Optional[VoiceInterface]]:
    """
    创建语音接口实例
    Create voice interface instance
    
    Args:
        config_path (Optional[str]): 配置文件路径 / Configuration file path
        initialize_all (bool): 是否初始化所有模块 / Whether to initialize all modules
        
    Returns:
        Tuple[bool, str, Optional[VoiceInterface]]: (success, message, voice_interface)
    """
    try:
        interface = VoiceInterface(config_path)
        
        if initialize_all:
            success, msg, _ = interface.initialize_all()
            if success:
                return True, "Voice interface created and initialized successfully", interface
            else:
                return False, f"Failed to initialize voice interface: {msg}", None
        else:
            return True, "Voice interface created successfully", interface
            
    except Exception as e:
        return False, f"Failed to create voice interface: {str(e)}", None